{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Assignment 1: K-Nearest Neighbor (10 marks)\n",
    "\n",
    "Student Name:Zhuoya ZHOU\n",
    "\n",
    "\n",
    "## General info\n",
    "\n",
    "<b>Due date</b>: Friday, 12 August 2022 5pm\n",
    "\n",
    "<b>Submission method</b>: Canvas submission\n",
    "\n",
    "<b>Submission materials</b>: completed copy of this iPython notebook\n",
    "\n",
    "<b>Late submissions</b>: -10% per day up to 5 days (both weekdays and weekends count). Submissions more than 5 days late will not be accepted (resul in a mark of 0).\n",
    "<ul>\n",
    "    <li>one day late, -1.0;</li>\n",
    "    <li>two days late, -2.0;</li>\n",
    "    <li>three days late, -3.0;</li>\n",
    "    <li>four days late, -4.0;</li>\n",
    "    <li>five days late, -5.0;</li>\n",
    "</ul>\n",
    "\n",
    "<b>Extensions</b>: Students who are demonstrably unable to submit a full solution in time due to medical reasons or other trauma, may apply for an extension.  In these cases, you should email <a href=\"mailto:hasti.samadi@unimelb.edu.au\">Hasti Samadi</a> as soon as possible after those circumstances arise. If you attend a GP or other health care service as a result of illness, be sure to provide a Health Professional Report (HPR) form (get it from the Special Consideration section of the Student Portal), you will need this form to be filled out if your illness develops into something that later requires a Special Consideration application to be lodged. You should scan the HPR form and send it with the extension requests.\n",
    "\n",
    "<b>Marks</b>: This assignment will be marked out of 10, and make up 10% of your overall mark for this subject.\n",
    "\n",
    "<b>Materials</b>: See [Using Jupyter Notebook and Python page](https://canvas.lms.unimelb.edu.au/courses/126693/pages/python-and-jupyter-notebooks?module_item_id=3950453) on Canvas (under Modules> Coding Resources) for information on the basic setup required for this class, including an iPython notebook viewer.If your iPython notebook doesn't run on the marker's machine, you will lose marks. <b> You should use Python 3</b>.  \n",
    "\n",
    "\n",
    "<b>Evaluation</b>: Your iPython notebook should run end-to-end without any errors in a reasonable amount of time, and you must follow all instructions provided below, including specific implementation requirements and instructions for what needs to be printed (please avoid printing output we don't ask for). You should edit the sections below where requested, but leave the rest of the code as is. You should leave the output from running your code in the iPython notebook you submit, to assist with marking. The amount each section is worth is given in parenthesis after the instructions. \n",
    "\n",
    "You will be marked not only on the correctness of your methods, but also the quality and efficency of your code: in particular, you should be careful to use Python built-in functions and operators when appropriate and pick descriptive variable names that adhere to <a href=\"https://www.python.org/dev/peps/pep-0008/\">Python style requirements</a>. If you think it might be unclear what you are doing, you should comment your code to help the marker make sense of it. We reserve the right to deduct up to 2 marks for unreadable or exessively inefficient code.\n",
    "\n",
    "<b>Updates</b>: Any major changes to the assignment will be announced via Canvas. Minor changes and clarifications will be announced on the discussion board (Piazza -> Assignments -> A1); we recommend you check it regularly.\n",
    "\n",
    "<b>Academic misconduct</b>: While you may discuss this homework in general terms with other students, it ultimately is still an individual task. Reuse of code or other instances of clear influence will be considered cheating. Please check the <a href=\"https://canvas.lms.unimelb.edu.au/courses/126693/modules#module_734188\">CIS Academic Honesty training</a> for more information. We will be checking submissions for originality and will invoke the University’s <a href=\"http://academichonesty.unimelb.edu.au/policy.html\">Academic Misconduct policy</a> where inappropriate levels of collusion or plagiarism are deemed to have taken place.\n",
    "\n",
    "**IMPORTANT**\n",
    "\n",
    "Please carefully read and fill out the <b>Authorship Declaration</b> form at the bottom of the page. Failure to fill out this form results in the following deductions: \n",
    "<UL TYPE=”square”>\n",
    "<LI>missing Authorship Declaration at the bottom of the page, -5.0\n",
    "<LI>incomplete or unsigned Authorship Declaration at the bottom of the page, -3.0\n",
    "</UL>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Overview\n",
    "\n",
    "In this homework, you'll be applying the K-nearest neighbor (KNN) classification algorithm to a real-world machine learning data set. In particular, we will predict the affordability of a car given a diverse set of features, including the make, engine type, style,  and horsepower and other descriptive properties of the car.\n",
    "\n",
    "Firstly, you will read in the dataset into a train and a test set, and you will create two feature sets (Q1). Secondly, you will implement different distance functions (Q2). Thirdly, you will implement one KNN classifier (Q3, Q4) and apply it to the data set using different distance functions and parameter K (Q5). Finally, you will assess the quality of your classifier by comparing its class predictions to the gold standard labels (Q6).\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Question 1: Loading the data (0.5 marks)\n",
    "\n",
    "**Instructions:** For this assignment we will develop a K-Nearest Neighbors (KNN) classifier to predict the \n",
    "affordability of cars. The list of classes is:\n",
    "\n",
    "```\n",
    "cheap\n",
    "affordable\n",
    "expensive\n",
    "very expensive\n",
    "```\n",
    "\n",
    "We use a modified version of the Car data set from the UCI Machine learning repository.\n",
    "\n",
    "The original data can be found here: https://archive.ics.uci.edu/ml/datasets/Automobile\n",
    "\n",
    "The dataset consists of 204 instances. Each instance corresponds to a car which has a unique identifier (X; first field) and is characterized with 24 features as described in the file *car.names* which is provided as part of this assignment.\n",
    "\n",
    "You need to first obtain this dataset, which is on Canvas (assignment 1). The files *car.features* and *car.labels* contain the data we will use in this notebook. Make sure the files are saved in the same folder as this notebook. \n",
    "\n",
    "Both files are in comma-separated value format. The first line in each file is a header, naming each feature (or label).\n",
    "\n",
    "*car.features* contains 204 instances, one line per instance. The first field is the unique instance identifier. The following fields contain the 24 features, as described in the file *car.names*.\n",
    "\n",
    "*car.labels* contains the gold labels (i.e., one of the four classes above), one instance per line. Again, the first field is the instance identifier, and the second field the instance label.\n",
    "\n",
    "*car.names* contains additional explanations about the data set and the features.\n",
    "\n",
    "All feature values are floats, and for Questions 1 through 5, we make the simplifying assumption that all values are indeed real-valued. You may want to revisit this assumption in Question 6."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "**Task**: Read the two files  \n",
    "1. create a **training_feature** set (list of features for the first 163 instances in the car.* files) and a **training_label** set (list of labels for the corresponding). \n",
    "2. create a **test_feature** set (list of features of the remaining instances in the car.* files) and a **test_label** set (list of labels for the corresponding). \n",
    "---------\n",
    "- Do **not** shuffle the data.\n",
    "- Do **not** modify feature or label representations. \n",
    "- Features must be represented as floats.\n",
    "--------\n",
    "You may use any Python packages you want, but not change the specified data types (i.e., they should be of type List, and *not* dataframe, dictionary etc)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "number of train/test instances: 163 41\n",
      "number of train/test features: 24 24\n"
     ]
    }
   ],
   "source": [
    "data = open(\"car.features\", 'r').readlines()\n",
    "labels = open(\"car.labels\", 'r').readlines()\n",
    "\n",
    "train_features = []\n",
    "train_labels   = []\n",
    "test_features = []\n",
    "test_labels   = []\n",
    "\n",
    "\n",
    "###########################\n",
    "## YOUR CODE BEGINS HERE\n",
    "###########################\n",
    "for i in range(1,len(data)):\n",
    "    one_row_feature = data[i].split(',')\n",
    "    one_row_label = labels[i].strip().split(',')[1]\n",
    "    one_row_feature_float = []\n",
    "    for j in range(1,len(one_row_feature)):\n",
    "        one_row_feature_float.append(float(one_row_feature[j])) \n",
    "        \n",
    "    if i<=163:\n",
    "        train_features.append(one_row_feature_float)\n",
    "        train_labels.append(one_row_label)\n",
    "    else:\n",
    "        test_features.append(one_row_feature_float)\n",
    "        test_labels.append(one_row_label)\n",
    "###########################\n",
    "## YOUR CODE ENDS HERE\n",
    "###########################\n",
    "\n",
    "print(\"number of train/test instances:\",len(train_features), len(test_features))\n",
    "print(\"number of train/test features:\",len(train_features[40]), len(test_features[1]))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Question 2: Distance Functions [1.5 marks]\n",
    "\n",
    "<b>Instructions</b>: Implement the three distance functions specified below. \n",
    "\n",
    "1. Euclidean distance\n",
    "2. Cosine distance\n",
    "3. Chebyshev distance, defined as:\n",
    "    \n",
    "    $d(x,y)=\\max_{i}|x_i-y_i|$\n",
    "    \n",
    "\n",
    "Each distance function takes as input\n",
    "- Two feature vectors (each of type List)\n",
    "\n",
    "and returns as output\n",
    "- The distance between the two feature vectors (float)\n",
    "\n",
    "------------\n",
    "\n",
    "Use <b>only</b> the library imported below, i.e., <b>do not</b> use implementations from any other Python library. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "600.17572\n",
      "600.0\n",
      "2e-05\n"
     ]
    }
   ],
   "source": [
    "import math\n",
    "\n",
    "\n",
    "def euclidean_distance(fw1, fw2):\n",
    "    # insert code here\n",
    "    sum = 0\n",
    "    for a,b in zip(fw1,fw2):\n",
    "        sum += (a-b)**2\n",
    "    distance = math.sqrt(sum)\n",
    "    return distance\n",
    "\n",
    "\n",
    "def cosine_distance(fw1, fw2):\n",
    "    # insert code here\n",
    "    fw1_fw2 =0\n",
    "    fw1d = 0\n",
    "    fw2d = 0\n",
    "    for a,b in zip(fw1,fw2):\n",
    "        fw1_fw2 += a*b\n",
    "        fw1d += a*a\n",
    "        fw2d += b*b\n",
    "    fw1d = math.sqrt(fw1d)\n",
    "    fw2d = math.sqrt(fw2d)\n",
    "    distance = 1 - fw1_fw2/(fw1d*fw2d)    \n",
    "    return distance\n",
    "\n",
    "\n",
    "def chebyshev_distance(fw1, fw2):\n",
    "    # insert code here\n",
    "    distance = 0\n",
    "    for a,b in zip(fw1,fw2):\n",
    "        distance = max(distance, abs(a-b))\n",
    "    return distance\n",
    "\n",
    "###########################\n",
    "## YOUR CODE ENDS HERE\n",
    "###########################\n",
    "\n",
    "print(round(euclidean_distance(train_features[100],test_features[2]), 5))\n",
    "print(round(chebyshev_distance(train_features[100],test_features[2]), 5))\n",
    "print(round(cosine_distance(train_features[100],test_features[2]), 5))\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Question 3: KNN Classifier [2.0 marks]\n",
    "\n",
    "<b>Instructions</b>: Here, you implement your KNN classifier. It takes as input \n",
    "- training data features\n",
    "- training data labels\n",
    "- test data features\n",
    "- parameter K\n",
    "- distance function(s) based on which nearest neighbors will be identified\n",
    "\n",
    "It returns as output \n",
    "- the predicted labels for the test data\n",
    "\n",
    "**Ties among distances**. If there are more than K instances with the same (smallest) distance value, consider the first K. For example, for K=1 if you have 3 instances (with identifiers i = 3, 12, 54) that all have the same distance to your test instance (e.g., 0.641), the instance with the smallest identifier should be selected as the nearest neighbor (in this case i = 3).\n",
    "\n",
    "**Ties at prediction time.** Ties can also occur at class prediction time when two (or more) classes are supported by the same number of neighbors. In that case choose the class of the 1 nearest neighbor. The \"1 nearest neighbor\" refers only to those classes represented with the maximum support in the neighborhood. E.g., for K = 5, with a neighborhood ordered by distance: {'cheap', 'expensive', 'affordable', expensive', 'affordable'} you would choose the 1 nearest neighbor among {'expensive','affordable'}.\n",
    "\n",
    "-----------\n",
    "\n",
    "**You should implement the classifier from scratch yourself**, i.e., <b> you must not</b> use an existing implementation in any Python library. You may use Python packages (e.g., math, numpy, collections, ...) to help with your implementation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "from collections import Counter\n",
    "def KNN(train_features, train_labels, test_features, k, dist_fun, weighted=False):\n",
    "    \n",
    "    predictions = []\n",
    "    \n",
    "    ##########################\n",
    "    # Your answer BEGINS HERE\n",
    "    ##########################\n",
    "    for test_item in test_features:\n",
    "        distance = []\n",
    "        for train_item in train_features:\n",
    "            distance.append(dist_fun(train_item, test_item))\n",
    "        sorted_distance = sorted(distance)\n",
    "        k_distance = sorted_distance[k-1]   \n",
    "        \n",
    "        label_list=[]\n",
    "        distance_list=[]\n",
    "        distance2score={}  \n",
    "        \n",
    "        count = 0 \n",
    "        for i,j in zip(distance, train_labels):\n",
    "            if i < k_distance :\n",
    "                label_list.append(j)\n",
    "                distance_list.append(i)\n",
    "                count+=1\n",
    "                \n",
    "                if weighted:\n",
    "                    distance2score[j] = distance2score.get(j,0) + 1./(i + 1e-6)\n",
    "                else:\n",
    "                    distance2score[j] = distance2score.get(j,0) + 1\n",
    "        \n",
    "        for i,j in zip(distance, train_labels):\n",
    "            if i == k_distance and count<k:\n",
    "                label_list.append(j)\n",
    "                distance_list.append(i)\n",
    "                count+=1\n",
    "                \n",
    "                if weighted:\n",
    "                    distance2score[j] = distance2score.get(j,0) + 1./(i + 1e-6)\n",
    "                else:\n",
    "                    distance2score[j] = distance2score.get(j,0) + 1\n",
    "       \n",
    "        items_sorted=sorted(distance2score.items(),key=lambda t:t[1])\n",
    "        max_label_score = items_sorted[-1][1]\n",
    "        min_distance = float('inf')\n",
    "        pred = None\n",
    "        for i,j in zip(label_list, distance_list):\n",
    "            if distance2score[i] == max_label_score and j < min_distance:\n",
    "                min_distance = j\n",
    "                pred = i\n",
    "        predictions.append(pred)\n",
    " \n",
    "        \n",
    "    ###########################\n",
    "    ## Your answer ENDS HERE\n",
    "    ###########################\n",
    "        \n",
    "    return predictions\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Question 4: Weighted KNN Classifier [1.0 mark]\n",
    "\n",
    "<b>Instructions</b>: Extend your implementation of the KNN classifier in Question 3 to a Weighted KNN classifier. You should change the code in the cell above. Use Inverse Distance as weights:\n",
    "\n",
    "$w_j=\\frac{1}{d_j+\\epsilon}$\n",
    "\n",
    "where\n",
    "\n",
    "- $d_j$ is the distance of of the jth nearest neighbor to the test instance\n",
    "- $\\epsilon=0.000001$\n",
    "\n",
    "Use the Boolean parameter `weighted` to specify the KNN version when calling the function."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Question 5: Applying your KNN classifiers to the Car Dataset [0.5 marks]\n",
    "\n",
    "**Using the functions you have implemented above, please**\n",
    "\n",
    "<b> 1. </b>\n",
    "For each of the distance functions you implemented in Question 2, construct (a) Nine majority voting KNN classifiers and (b) Nine weighted KNN classifiers, respectively, with \n",
    "\n",
    "- K=1\n",
    "- K=5\n",
    "- k=20\n",
    "\n",
    "You will obtain a total of 18 (3 distance functions x 3 K values x 2 KNN versions) classifiers.\n",
    "\n",
    "<b> 2. </b>\n",
    "Compute the test accuracy for each model, where the accuracy is the fraction of correctly predicted labels over all predictions. Use the `accuracy_score` function from the `sklearn.metrics` package to obtain your accuracy.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Results on the *full* feature set\n",
      "\n",
      "euclidean (majority vote)\n",
      "K=1 0.756\n",
      "K=5 0.707\n",
      "K=20 0.634\n",
      "-----------\n",
      "euclidean (weighted)\n",
      "K=1 0.756\n",
      "K=5 0.683\n",
      "K=20 0.756\n",
      "\n",
      "cosine (majority vote)\n",
      "K=1 0.805\n",
      "K=5 0.707\n",
      "K=20 0.659\n",
      "-----------\n",
      "cosine (weighted)\n",
      "K=1 0.805\n",
      "K=5 0.732\n",
      "K=20 0.707\n",
      "\n",
      "chebyshev (majority vote)\n",
      "K=1 0.683\n",
      "K=5 0.634\n",
      "K=20 0.561\n",
      "-----------\n",
      "chebyshev (weighted)\n",
      "K=1 0.683\n",
      "K=5 0.683\n",
      "K=20 0.756\n"
     ]
    }
   ],
   "source": [
    "from sklearn.metrics import accuracy_score\n",
    "\n",
    "########################\n",
    "# Your code STARTS HERE\n",
    "########################\n",
    "\n",
    "\n",
    "accuracy_knn_euc_1 = accuracy_score(test_labels, KNN(train_features, train_labels, test_features, 1, euclidean_distance, weighted=False))\n",
    "accuracy_knn_euc_5 = accuracy_score(test_labels, KNN(train_features, train_labels, test_features, 5, euclidean_distance, weighted=False))\n",
    "accuracy_knn_euc_20 = accuracy_score(test_labels, KNN(train_features, train_labels, test_features, 20, euclidean_distance, weighted=False))\n",
    " \n",
    "accuracy_knn_euc_1_w = accuracy_score(test_labels, KNN(train_features, train_labels, test_features, 1, euclidean_distance, weighted=True))\n",
    "accuracy_knn_euc_5_w = accuracy_score(test_labels, KNN(train_features, train_labels, test_features, 5, euclidean_distance, weighted=True))\n",
    "accuracy_knn_euc_20_w = accuracy_score(test_labels, KNN(train_features, train_labels, test_features, 20, euclidean_distance, weighted=True))\n",
    "\n",
    "accuracy_knn_cos_1 = accuracy_score(test_labels, KNN(train_features, train_labels, test_features, 1, cosine_distance, weighted=False))\n",
    "accuracy_knn_cos_5 =  accuracy_score(test_labels, KNN(train_features, train_labels, test_features, 5, cosine_distance, weighted=False))\n",
    "accuracy_knn_cos_20 = accuracy_score(test_labels, KNN(train_features, train_labels, test_features, 20, cosine_distance, weighted=False))\n",
    "\n",
    "accuracy_knn_cos_1_w = accuracy_score(test_labels, KNN(train_features, train_labels, test_features, 1, cosine_distance, weighted=True))\n",
    "accuracy_knn_cos_5_w = accuracy_score(test_labels, KNN(train_features, train_labels, test_features, 5, cosine_distance, weighted=True)) \n",
    "accuracy_knn_cos_20_w = accuracy_score(test_labels, KNN(train_features, train_labels, test_features, 20, cosine_distance, weighted=True))\n",
    "\n",
    "accuracy_knn_che_1 = accuracy_score(test_labels, KNN(train_features, train_labels, test_features, 1, chebyshev_distance, weighted=False))\n",
    "accuracy_knn_che_5 = accuracy_score(test_labels, KNN(train_features, train_labels, test_features, 5, chebyshev_distance, weighted=False))\n",
    "accuracy_knn_che_20 = accuracy_score(test_labels, KNN(train_features, train_labels, test_features, 20, chebyshev_distance, weighted=False))\n",
    " \n",
    "accuracy_knn_che_1_w = accuracy_score(test_labels, KNN(train_features, train_labels, test_features, 1, chebyshev_distance, weighted=True))\n",
    "accuracy_knn_che_5_w = accuracy_score(test_labels, KNN(train_features, train_labels, test_features, 5, chebyshev_distance, weighted=True))\n",
    "accuracy_knn_che_20_w = accuracy_score(test_labels, KNN(train_features, train_labels, test_features, 20, chebyshev_distance, weighted=True))\n",
    "\n",
    "########################\n",
    "# Your code ENDS HERE\n",
    "########################\n",
    "\n",
    "\n",
    "\n",
    "print(\"Results on the *full* feature set\")\n",
    "\n",
    "print(\"\\neuclidean (majority vote)\")\n",
    "print(\"K=1\", round(accuracy_knn_euc_1, 3))\n",
    "print(\"K=5\", round(accuracy_knn_euc_5, 3))\n",
    "print(\"K=20\", round(accuracy_knn_euc_20, 3))\n",
    "\n",
    "print(\"-----------\\neuclidean (weighted)\")\n",
    "print(\"K=1\", round(accuracy_knn_euc_1_w, 3))\n",
    "print(\"K=5\", round(accuracy_knn_euc_5_w, 3))\n",
    "print(\"K=20\", round(accuracy_knn_euc_20_w, 3))\n",
    "\n",
    "print(\"\\ncosine (majority vote)\")\n",
    "print(\"K=1\", round(accuracy_knn_cos_1, 3))\n",
    "print(\"K=5\", round(accuracy_knn_cos_5, 3))\n",
    "print(\"K=20\", round(accuracy_knn_cos_20, 3))\n",
    "\n",
    "print(\"-----------\\ncosine (weighted)\")\n",
    "print(\"K=1\", round(accuracy_knn_cos_1_w, 3))\n",
    "print(\"K=5\", round(accuracy_knn_cos_5_w, 3))\n",
    "print(\"K=20\", round(accuracy_knn_cos_20_w, 3))\n",
    "\n",
    "print(\"\\nchebyshev (majority vote)\")\n",
    "print(\"K=1\", round(accuracy_knn_che_1, 3))\n",
    "print(\"K=5\", round(accuracy_knn_che_5, 3))\n",
    "print(\"K=20\", round(accuracy_knn_che_20, 3))\n",
    "\n",
    "print(\"-----------\\nchebyshev (weighted)\")\n",
    "print(\"K=1\", round(accuracy_knn_che_1_w, 3))\n",
    "print(\"K=5\", round(accuracy_knn_che_5_w, 3))\n",
    "print(\"K=20\", round(accuracy_knn_che_20_w, 3))\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Question 6: Analysis [4.5 marks]\n",
    "\n",
    "1. Consider the following features: make, fuel-type, body-style, and num-of-doors. Assume we intend to use KNN with euclidean distance, for each of the above features, would you change the approach we chose to convert nominal to numeric features? If yes, explain what approach you would select and discuss one benefit and one drawback of your proposed approach.**[0.75 marks]** \n",
    "\n",
    "    \n",
    "2. Consider these two sets of attributes: (curb-weight,engine-size) and (compression-ratio, peak-rpm)\n",
    "\n",
    "    (a) For each set of features, create a scatter plot of data points coloring instances from each class differently. You should produce **two plots** which show the scattered data points colored by class label. Label the x-axis and y-axis. [*N.B. you may use libraries like <a href=\"https://matplotlib.org/stable/tutorials/introductory/usage.html#sphx-glr-tutorials-introductory-usage-py\">matplotlib</a> or <a href=\"https://seaborn.pydata.org/introduction.html\">seaborne</a>*] **[1 mark]**\n",
    "    \n",
    "    (b) Which feature set is more informative in the context of this classification task and why?**[0.5 marks]**\n",
    "    \n",
    "    (c) What do you observe about the relationship between features in each feature set and how did you come to that conclusion?**[0.25 marks]**\n",
    "    \n",
    "    \n",
    "3. Discuss the appropriateness of each of the distance functions for our *car* data set. Where appropriate, explain why you expect them to perform poorly referring to both their mathematical properties and the given feature set. **[0.75 marks]**\n",
    "\n",
    "    \n",
    "\n",
    "4. Does the Weighted KNN outperform the Majority voting version, or vice versa? Hypothesize why (not). **[0.75 mark]**\n",
    "\n",
    "\n",
    "\n",
    "5. Do you think the accuracy is an appropriate evaluation metric for the *car* data set? Why (not)? **[0.5 marks]**\n",
    "\n",
    " \n",
    "\n",
    "<b>Each question should be answered in no more than 3-4 sentences.</b>\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "1 One-hot encoding is preferred. It is a sequence or vector of n-dimensional 0 or 1 representions. Each feature optional value represents one dimension, 1 means the current feature value is active. Benefit: Eliminate the nuisance of extra information in low dimensions that may be caused by the size of the numbers. Drawback: Space consumption due to too many dimensions.\n",
    "\n",
    "2\n",
    "\n",
    "*Type code for 2.(a) in the cell below, and answer 2.(b) and 2.(c) below*\n",
    "\n",
    "2b)The first graph that is about the \"curb-weight\" and \"engine-size\" is more informative. Since different classes have clear boundary, which can be distinguished more clearly. However, in the second diagram, all the classes are packed together and it is not possible to judge them well.\n",
    "\n",
    "2c)The curb-weight and engine-size are positive related or consistent, as we can see, the engine-size is large when curb-weight is large, and vice versa. But compression-ratio and peak-rpm are hard to see their relationship. And we can see the peak-rpm has a range of values when compression-ratio is small.\n",
    "\n",
    "3 Cosine distance is more accurate. Since both Euclidean distance and Chebyshev distance consider every feature but have different scales. For example, peak-rpm is from 4150 to 6600, which has more effects than engine-size that is from 0 to 1. However, engine-size is more informative from above discussion. Fortunately, cosine distance can lessen the detrimental impact of value range by normalising.  \n",
    "\n",
    "4 The performance of the weighted KNN outperforms the Majority voting version, as we can see comparing cosine (weighted) and cosine(majority vote) in the last section. Since there will be a lot of noises from far neighrbors when chosing large K and weighted KNN reduce the effects from far neighbors, but majority vote not.\n",
    "\n",
    "5 No. From the cell bellow, we can see this is very imbalanced dataset, since more than half of the data falls into the \"cheap\" class. So the computer will have the accuracy of at least 50% when mostly cheap is chosen.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Counter({'cheap': 81, 'affordable': 53, 'expensive': 21, 'very expensive': 8})\n",
      "Counter({'cheap': 20, 'affordable': 14, 'expensive': 5, 'very expensive': 2})\n"
     ]
    }
   ],
   "source": [
    "from collections import Counter\n",
    "print(Counter(train_labels))\n",
    "print(Counter(test_labels))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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4NixY3Ts2JGtW7eycuVKLr/8coYOHUr79u359a9/TUlJCeAkpOvbty/du3dnxIgRvmGjrVu35oEHHqB79+507tyZzz//HID333+frl270rVrV7p168aPP/7I3r176dSpEwB9+vRh27ZtvjoOGDCA9evXc+zYMX75y1/Su3dvunXrxj/+8Y9qOQfGmLon7gJB9u5spn00jdxjuShK7rFcpn00rcrBYMeOHcyfP58PP/yQzZs3k5iYyBdffMG1117Lfffdxx/+8AfGjBnju0CvXbuWp556iu3bt/PVV1+xePFiDh8+zIwZM/jXv/7Fxo0b6dmzJ0888YTvPZo0acLGjRu5++67efzxxwF4/PHHmTt3Lps3b2bVqlWkpKSUqteoUaNYsMBJsZ2bm0tubi49e/bk4YcfZuDAgaxdu5b33nuPSZMmcezYsSqdA2NM3RR3M4tnb5xNQXHpjJ4FxQXM3jiboW2HVvq477zzDhs2bKBXr14AnDhxgmbNmjF16lR69epFcnIyc+bM8e3fu3dv2rZtC8Do0aNZvXo1ycnJbN++nX79+gFw6tQpXz4igBtuuAGAHj16sHjxYgD69evHPffcw80338wNN9xAy5alk+eNHDmSrKwsHnzwQRYsWODrO1ixYgVLly71BZSCggK++eYbS/VgTByKu0Dw7bFvK1QeLlXl1ltv5ZFHHilVnpuby9GjRyksLKSgoICGDRsCZdNIiwiqypVXXslrr73m+h7elNaJiYkUFRUBMGXKFIYOHcpbb71Fv379WL58Ocl+uddbtGhB48aN2bJlC/Pnz+fpp5/21ffvf/877du3r9LnNsbUfXHXNHRuw3MrVB6uQYMGsWjRIg4ePAg4aai//vprxo4dy0MPPcTNN9/M5MmTffuvXbuWPXv2UFJSwvz587n00kvp06cPH374IV9++SXgrEq2c+fOkO/71Vdf0blzZyZPnkyvXr18fQf+Ro0axWOPPUZ+fj6ZmZmAkwr7qaee8q2RsGnTpip9fmNM3RV3gWB89/EkJ5ZerSg5MZnx3cdX6bgdOnRgxowZZGVlkZmZyZVXXsm8efNISkripptuYsqUKaxbt453330XgF69ejFu3DgyMjJo06YNP/vZz2jatCkvvvgio0ePJjMzk759+7pe2P09+eSTdOrUiczMTJKSkrjqqqvK7DN8+HBef/11Ro48nWjv/vvvp7CwkMzMTDp27Mj9999fpc9vjKm7IpqGWkSGALOBROD/VPXRgO3nAfOANM8+U1T1rVDHrI401Nm7s5m9cTbfHvuWcxuey/ju46vUP1BRK1eu5PHHH+fNN9+ssfeszSwNtTGRF5U01CKSCMwFrgRygHUislRVt/vtdh+wQFX/IiIdgLeA1pGqk9fQtkNr9MJvjDG1WSSbhnoDX6rqblU9BbwOXBewjwJnex6nAgciWJ9aY8CAAXY3YIypNSIZCFoA+/ye53jK/E0DxohIDs7dwH+6HUhE7hKR9SKy/tChQ5GoqzHGxK1odxaPBl5U1ZbA1cBLIlKmTqr6rKr2VNWeTZs2rfFKGmNMLItkINgPtPJ73tJT5u8OYAGAqn4MJANNIlgnY4wxASIZCNYB7USkjYjUB24Elgbs8w0wCEBEMnACgbX9GGNMDYpYIFDVImAcsBzYgTM6aJuITBeRaz27/Rdwp4h8CrwG3KaRHM9qqtUll1wS7SoYY6pBRFNMeOYEvBVQNtXv8XagXyTrUNupKqpKQkK0u2sq7qOPPop2FYwx1aDuXX2qQf6yZewaOIgdGR3YNXAQ+cuWVel4U6ZMYe7cub7n06ZN8yVzmzlzJr169SIzM5MHHngAgL1799K+fXtuueUWOnXqxEMPPcSECRN8r3/uueeYOHFimfdxS1H99ddf065dOw4fPkxJSQmXXXYZK1asYO/evVx00UXcfPPNZGRkMHz4cI4fPw7Ahg0b6N+/Pz169GDw4MHk5uYCzrDWyZMn07t3by688EJWrVoFwLZt23zptTMzM9m1axcAZ555JgA33ngj2dmns7fedtttLFq0iOLiYiZNmuT7/M8880yVzrMxJkK830jryk+PHj000Pbt28uUBZO3dKnu6NJVt7e/yPezo0tXzVu6NOxjBNq4caNefvnlvucZGRn6zTff6PLly/XOO+/UkpISLS4u1qFDh+r777+ve/bsURHRjz/+WFVVf/zxR23btq2eOnVKVVX79u2rW7ZsKfUehw4d0ssuu0yPHj2qqqqPPvqoPvjgg6qq+txzz+nw4cP1scce07vuuktVVffs2aOArl69WlVVb7/9dp05c6aeOnVK+/btqwcPHlRV1ddff11vv/12VVXt37+/3nPPPaqqmp2drYMGDVJV1XHjxunLL7+sqqonT57U48ePq6pqw4YNVVV18eLFesstt/i2t2zZUo8fP67PPPOMPvTQQ6qqWlBQoD169NDdu3eXOX8V+fczxlQOsF6DXFfjLvvowVlPogWl01BrQQEHZz1J6rBhlTpmt27dOHjwIAcOHODQoUM0atSIVq1aMXv2bFasWEG3bt0AOHr0KLt27eK8887j/PPPp0+fPoDzzXrgwIG8+eabZGRkUFhYSOfOnUu9x5o1a4KmqP7Vr37FwoULefrpp9m8ebPvNa1atfLtP2bMGObMmcOQIUPYunUrV155JQDFxcWkp6f7XuOf6nrv3r0A9O3bl4cffpicnBxuuOEG2rVrV6puV111FePHj+fkyZP885//5PLLLyclJYUVK1awZcsW32pp+fn57Nq1izZt2lTqPBtjIiPuAkGRpxkk3PJwjRgxgkWLFvHtt98yatQowLnbuvfeexk7dmypfffu3etLR+31q1/9iv/+7//moosu4vbbby9zfA2Rovr48ePk5OQATrA566yzgOCprjt27MjHH3/s+jncUl3fdNNNXHzxxWRnZ3P11VfzzDPPMHDgQN9rkpOTGTBgAMuXL2f+/PnceOONvjo/9dRTDB48OMhZM8aEY+Vfp5P07ALS8ovJS02k8K6RDLhjavkvDFPc9RHU8/v2G055uEaNGsXrr7/OokWLGDFiBOCken7++ed9y03u37/fl6Y60MUXX8y+fft49dVXGT16dJntoVJUT548mZtvvpnp06dz5513+l7zzTff+C74r776Kpdeeint27fn0KFDvvLCwsJSS1m62b17N23btuV3v/sd1113HVu2bHH9/C+88AKrVq1iyJAhvs//l7/8hcLCQgB27txpq6AZU0Er/zqdtCdf45z8YhKAc/KLSXvyNVb+dXq1vUfcBYJmEycgyaXTUEtyMs0mTqjScTt27MiPP/5IixYtfE0tWVlZ3HTTTfTt25fOnTszfPhwfvzxx6DHGDlyJP369aNRo0ZltgVLUf3++++zbt06XzCoX78+L7zwAgDt27dn7ty5ZGRk8P3333P33XdTv359Fi1axOTJk+nSpQtdu3Ytd/TPggUL6NSpE127dmXr1q3ccsstZfbJysri/fff54orrqB+/fqAc5fToUMHunfvTqdOnRg7dqzvLsMYE56kZxfQoLB0WYNCp7y6RDQNdSRURxrq/GXLODjrSYpyc6mXnk6z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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYsAAAEGCAYAAACUzrmNAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAAsTAAALEwEAmpwYAAA2eUlEQVR4nO3deXxU1fn48c+TEAibCQhIWBTwpyyBCGF1qSDUgIKKfgWkaEGsWq0aoOULtApBsfZbrBBcarWIVFxYVCqgBQuigiIQRGRTFFCWICAmaiCQ5fn9cW+GbJOZSTKZCTzv12ucuWfOvfPMMM6Te86554iqYowxxpQlItQBGGOMCX+WLIwxxvhkycIYY4xPliyMMcb4ZMnCGGOMTzVCHUAwNGrUSFu1ahXqMIwxplpJS0s7qqqNS3vujEwWrVq1YuPGjaEOwxhjqhUR+cbbc9YMZYwxxidLFsYYY3yyZGGMMcanM7LPwhgTfDk5Oezfv5/s7OxQh2ICFB0dTYsWLYiKivJ7H0sWxphy2b9/P/Xr16dVq1aISKjDMX5SVb7//nv2799P69at/d7PkkV1t3QcpL0ImgcSCV1HwaAnQh2VOQtkZ2dboqiGRIRzzz2XI0eOBLSfJYvqbOk42Dj79Lbmnd62hGGqgCWK6qk8/27WwV2dpb0YWLkxxpSTJYvqTPMCKzfmLLFw4ULat2/PVVddBcDw4cNJSEhgxowZ5Tre3r176dixY5l1Vq9ezaBBg0p9rlWrVhw9erRcrx0urBmqOpPI0hODRFZ9LMaEkdmzZ/P8889zxRVXcOjQITZs2MBXX33l9/65ubnUqGE/j4XZp1GddR1VtM+icLkxYWbxpweYvvwLDmacoFlsbcb3b8vgLs0rfNzBgwezb98+srOzSU5O5tChQ6xZs4Y77riD66+/nuXLl3PgwAE6d+7Mk08+Sf369fntb3/L8ePHufDCC3nhhRdo0KABffr0oXPnzqxZs4bhw4fTp08fRo8eDUBSUpLn9fbu3cttt91GVlYWAE899RSXXXYZAD/++CMDBw7kq6++4qqrruKZZ54hIqJoA868efOYNWsWp06domfPnjzzzDNERlaDP/BU9Yy7de3aVc8aS8aqpjRQnXKOc79kbKgjMmeJ7du3+133zU37td2D7+gFE5Z6bu0efEff3LS/wnF8//33qqp6/PhxjY+P16NHj2rv3r11w4YNqqq6Z88ejY+P99Tv1KmTrl69WlVVH3roIU1OTlZV1d69e+s999xTpN7777+vqqp/+MMfPMfIysrSEydOqKrql19+qQW/N++9957WqlVLv/76a83NzdVf/vKXunDhQlVVveCCC/TIkSO6fft2HTRokJ46dUpVVe+55x6dO3duhT+D8ijt3w/YqF5+V+3Morob9ISNfDJhb/ryLziRU7TJ9EROHtOXf1Hhs4tZs2bx5ptvArBv3z527drltW5mZiYZGRn07t0bgJEjRzJkyBDP88OGDQMgIyODjIwMrrzySgBuu+023nnnHcC5GPG+++5j8+bNREZG8uWXX3r279GjB23atAGcfpI1a9Zw8803e55fuXIlaWlpdO/e3fkMTpygSZMmFXr/VSWoyUJEYoF/Ah0BBUYD/YE7gYJBvn9U1bfd+pOAO4A84AFVXe6WDwBSgUjgn6r6l2DGbYypXAczTgRU7q/Vq1fz3//+l48//pg6derQp0+fCl1RXrduXZ91ZsyYwXnnncdnn31Gfn4+0dHRnueKD0ktvq2qjBw5kscee6zcMYZKsEdDpQL/UdV2wCXADrd8hqp2dm8FiaIDcAsQDwwAnhGRSBGJBJ4GrgE6AMPdusaYaqJZbO2Ayv2VmZlJgwYNqFOnDjt37mTdunVl1o+JiaFBgwZ8+OGHALz00kues4zCYmNjiY2NZc2aNQC8/PLLRV4zLi6OiIgIXnrpJfLyTp8xrV+/nj179pCfn8/8+fO54oorihy3X79+LFq0iMOHDwNw7NgxvvnG66zgYSVoyUJEYoArgdkAqnpKVTPK2OUG4DVVPamqe4CvgB7u7StV3a2qp4DX3LrGmGpifP+21I4q2olbOyqS8f3bVui4AwYMIDc3l/bt2zNx4kR69erlc5+5c+cyfvx4EhIS2Lx5M5MnTy613pw5c/jd735H586dcZrzHffeey9z587lkksuYefOnUXORrp37859991H+/btad26NTfeeGORY3bo0IFp06aRlJREQkICV199Nenp6eV891VLCn8IlXpgkc7Ac8B2nLOKNCAZGA+MAn4ENgK/V9UfROQpYJ2qznP3nw284x5ugKr+xi2/DeipqvcVe727gLsAzj///K7VJVsbU13t2LGD9u3b+10/WKOhTPmU9u8nImmq2q20+sHss6gBJAL3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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "################################################\n",
    "# Your answer to Question 6 (2) STARTS HERE\n",
    "################################################\n",
    "def draw(feature1,feature2):\n",
    "    x_axis=[]\n",
    "    y_axis=[]\n",
    "    x_axis1=[]\n",
    "    y_axis1=[]\n",
    "    x_axis2=[]\n",
    "    y_axis2=[]\n",
    "    x_axis3=[]\n",
    "    y_axis3=[]\n",
    "    for x,y in zip(train_features, train_labels):\n",
    "        if y == \"affordable\":\n",
    "            x_axis.append(x[feature1])      \n",
    "            y_axis.append(x[feature2])  \n",
    "\n",
    "        elif y == \"cheap\":\n",
    "            x_axis1.append(x[feature1])\n",
    "            y_axis1.append(x[feature2])   \n",
    "\n",
    "        elif y == \"expensive\":\n",
    "            x_axis2.append(x[feature1])   \n",
    "            y_axis2.append(x[feature2])  \n",
    "\n",
    "        elif y == \"very expensive\":\n",
    "            x_axis3.append(x[feature1])    \n",
    "            y_axis3.append(x[feature2])   \n",
    "\n",
    "    plt.scatter(x_axis,y_axis,label=\"affordable\")\n",
    "    plt.scatter(x_axis1,y_axis1,label=\"cheap\")\n",
    "    plt.scatter(x_axis2,y_axis2,label=\"expensive\")\n",
    "    plt.scatter(x_axis3,y_axis3,label=\"very expensive\")\n",
    "\n",
    "    if feature1==12 and feature2==15:\n",
    "        plt.xlabel(\"curb-weight\")\n",
    "        plt.ylabel(\"engine-size\")\n",
    "    else:\n",
    "        plt.xlabel(\"compression-ratio\")   \n",
    "        plt.ylabel(\"peak-rpm\")\n",
    "    plt.legend()\n",
    "    plt.show()\n",
    "\n",
    "draw(12,15)\n",
    "draw(19,21)\n",
    "################################################\n",
    "# Your answer to Question 6 (2) ENDS HERE\n",
    "################################################\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<b>Authorship Declaration</b>:\n",
    "\n",
    "   (1) I certify that the program contained in this submission is completely\n",
    "   my own individual work, except where explicitly noted by comments that\n",
    "   provide details otherwise.  I understand that work that has been developed\n",
    "   by another student, or by me in collaboration with other students,\n",
    "   or by non-students as a result of request, solicitation, or payment,\n",
    "   may not be submitted for assessment in this subject.  I understand that\n",
    "   submitting for assessment work developed by or in collaboration with\n",
    "   other students or non-students constitutes Academic Misconduct, and\n",
    "   may be penalized by mark deductions, or by other penalties determined\n",
    "   via the University of Melbourne Academic Honesty Policy, as described\n",
    "   at https://academicintegrity.unimelb.edu.au.\n",
    "\n",
    "   (2) I also certify that I have not provided a copy of this work in either\n",
    "   softcopy or hardcopy or any other form to any other student, and nor will\n",
    "   I do so until after the marks are released. I understand that providing\n",
    "   my work to other students, regardless of my intention or any undertakings\n",
    "   made to me by that other student, is also Academic Misconduct.\n",
    "\n",
    "   (3) I further understand that providing a copy of the assignment\n",
    "   specification to any form of code authoring or assignment tutoring\n",
    "   service, or drawing the attention of others to such services and code\n",
    "   that may have been made available via such a service, may be regarded\n",
    "   as Student General Misconduct (interfering with the teaching activities\n",
    "   of the University and/or inciting others to commit Academic Misconduct).\n",
    "   I understand that an allegation of Student General Misconduct may arise\n",
    "   regardless of whether or not I personally make use of such solutions\n",
    "   or sought benefit from such actions.\n",
    "\n",
    "   <b>Signed by</b>: Zhuoya Zhou  \n",
    "   \n",
    "   <b>Dated</b>: 2022.8.7"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
